package br.com.sisgerenciamento.dao.pedido;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.hibernate.exception.ConstraintViolationException;

import br.com.sisgerenciamento.exceptions.AlterarException;
import br.com.sisgerenciamento.exceptions.ApplicationException;
import br.com.sisgerenciamento.exceptions.ExcluirException;
import br.com.sisgerenciamento.exceptions.InserirException;
import br.com.sisgerenciamento.generic.GenericDAO;
import br.com.sisgerenciamento.model.pedido.PedidoVO;
import br.com.sisgerenciamento.model.pedido.StatusPedidoEnum;
import br.com.sisgerenciamento.model.produto.ProdutoVO;
import br.com.sisgerenciamento.model.produto.TipoProdutoEnum;
import br.com.sisgerenciamento.model.produtoquantidade.ProdutoQuantidadeVO;
import br.com.sisgerenciamento.utilidades.TreatDate;


public class PedidoDAOServiceImpl extends GenericDAO< PedidoVO > implements PedidoDAOService{

	public PedidoVO inserir(PedidoVO vo) throws InserirException {
		return (PedidoVO) insert(vo);
	}

	public void alterar(PedidoVO vo) throws AlterarException {
		update(vo);
	}

	public void excluir(PedidoVO vo) throws ExcluirException {
		Transaction transaction = null;
		Session session = null;

		try {
			session = getSessionAberta();
			transaction = session.beginTransaction();

			if(vo.getProdutos() != null){
				for (ProdutoQuantidadeVO prod : vo.getProdutos()) {
					ProdutoVO produto = prod.getProduto();
					if(TipoProdutoEnum.PRONTA_ENTREGA.equals(produto.getTipo())){
						produto.setQuantidade( produto.getQuantidade() + prod.getQuantidade().intValue());
						session.update(produto);
					}
					session.delete( prod );
				}
			}
			if(vo.getLocacaoVO() != null)
				session.delete( vo.getLocacaoVO() );

			session.delete( vo );

			transaction.commit();
			session.close();

		} catch ( ConstraintViolationException e ) {
			if ( transaction != null ) {
				transaction.rollback();
			}
			if ( session != null ) {
				session.close();
			}

			throw new HibernateException( e.getMessage() );
		} catch ( Exception e ) {
			if ( transaction != null ) {
				transaction.rollback();
			}
			if ( session != null ) {
				session.close();
			}
			throw new HibernateException( e.getMessage() );
		}
	}

	public void cancelarPedido(PedidoVO vo) throws ExcluirException {
		Transaction transaction = null;
		Session session = null;

		try {
			session = getSessionAberta();
			transaction = session.beginTransaction();

			if(vo.getProdutos() != null){
				for (ProdutoQuantidadeVO prod : vo.getProdutos()) {
					ProdutoVO produto = prod.getProduto();
					if(TipoProdutoEnum.PRONTA_ENTREGA.equals(produto.getTipo())){
						produto.setQuantidade( produto.getQuantidade() + prod.getQuantidade().intValue());
						session.update(produto);
					}
				}
			}
			if(vo.getLocacaoVO() != null){
				session.delete( vo.getLocacaoVO() );
				vo.setLocacaoVO(null);
			}
			vo.setStatus(StatusPedidoEnum.CANCELADO);
			session.update( vo );

			transaction.commit();
			session.close();

		} catch ( ConstraintViolationException e ) {
			if ( transaction != null ) {
				transaction.rollback();
			}
			if ( session != null ) {
				session.close();
			}

			throw new HibernateException( e.getMessage() );
		} catch ( Exception e ) {
			if ( transaction != null ) {
				transaction.rollback();
			}
			if ( session != null ) {
				session.close();
			}
			throw new HibernateException( e.getMessage() );
		}
	}



	public PedidoVO consultar(Long codigo) throws ApplicationException {
		Session session = null;
		try {
			session = getSessionAberta();
			Criteria criteria = session.createCriteria(PedidoVO.class);
			criteria.add(Restrictions.eq("codigo", codigo));
			PedidoVO vo = (PedidoVO) consultar(criteria);
			return vo;
		} catch (Exception e) {
			throw new ApplicationException(e.getMessage());
		} finally {
			if (session != null)
				session.close();
		}
	}

	public List<PedidoVO> listarPorCliente(String nomeCliente) throws ApplicationException {
		Session session = null;
		try {
			session = getSessionAberta();
			Criteria criteria = session.createCriteria(PedidoVO.class);
			criteria.createAlias("cliente", "cliente");
			criteria.add(Restrictions.ilike("cliente.nome", "%"+nomeCliente+"%"));
			criteria.addOrder(Order.asc("codigo"));
			return filtro(criteria);
		} catch (Exception e) {
			throw new ApplicationException(e.getMessage());
		} finally {
			if (session != null)
				session.close();
		}
	}

	public List<PedidoVO> listarPedidosPorPerido(Date dataInicio, Date dataFim)
			throws ApplicationException {
		Session session = null;
		try {
			session = getSessionAberta();
			Criteria criteria = session.createCriteria(PedidoVO.class);
			criteria.createAlias("cliente", "cliente");
			criteria.add(Restrictions.between("dataEntrega", dataInicio, dataFim));
			criteria.addOrder(Order.asc("dataEntrega"));
			criteria.addOrder(Order.asc("horaEntrega"));
			return filtro(criteria);
		} catch (Exception e) {
			throw new ApplicationException(e.getMessage());
		} finally {
			if (session != null)
				session.close();
		}
	}

	public List<PedidoVO> listarPedidoPendentesEConfirmados() throws ApplicationException {
		Session session = null;
		try {
			session = getSessionAberta();
			Criteria criteria = session.createCriteria(PedidoVO.class);
			criteria.add(Restrictions.or(Restrictions.eq("status",StatusPedidoEnum.PRE_VENDA),Restrictions.eq("status",StatusPedidoEnum.CONFIRMADO)));  
			criteria.addOrder(Order.asc("codigo"));
			return filtro(criteria);
		} catch (Exception e) {
			throw new ApplicationException(e.getMessage());
		} finally {
			if (session != null)
				session.close();
		}
	}

	@SuppressWarnings("unchecked")
	public ArrayList<PedidoVO> buscarPedidoPorTipoLocacaoEPeriodo(Integer tipoLocacao, Date dataInicial, Date dataFinal)throws ApplicationException {
		Session session = null;

		StringBuilder hql = new StringBuilder();
		hql.append("SELECT ped ");		 
		hql.append("FROM PedidoVO ped ");
		hql.append("WHERE ped.locacaoVO.status = :status ");
		hql.append("AND ped.dataHoraEmissao between :dataInicial and :dataFinal");

		try {
			session = getSessionAberta();
			Query hqlQuery = session.createQuery(hql.toString());

			hqlQuery.setInteger("status", tipoLocacao);
			hqlQuery.setDate("dataInicial", dataInicial);
			hqlQuery.setDate("dataFinal", dataFinal);

			return (ArrayList<PedidoVO>) hqlQuery.list();
		} catch (Exception e) {
			throw new ApplicationException(e.getMessage());
		} finally {
			if (session != null)
				session.close();
		}
	}

	@SuppressWarnings("unchecked")
	public ArrayList<PedidoVO> listarImpressaoCozinhaPendente()
			throws ApplicationException {
		Session session = null;

		StringBuilder hql = new StringBuilder();
		hql.append("SELECT ped ");		
		hql.append("FROM PedidoVO ped ");
		hql.append("WHERE (impressoCozinha = :impressoCozinha OR impressoCozinha is null)");
		hql.append(" AND status is not :status ");
		try {
			session = getSessionAberta();
			Query hqlQuery = session.createQuery(hql.toString());

			hqlQuery.setBoolean("impressoCozinha", false);
			hqlQuery.setParameter("status", StatusPedidoEnum.PRE_VENDA);
			return (ArrayList<PedidoVO>) hqlQuery.list();
		} catch (Exception e) {
			throw new ApplicationException(e.getMessage());
		} finally {
			if (session != null)
				session.close();
		}
	}

	public void impressoCozinha(Long codPedido) throws  ApplicationException {
		Session session = null;

		StringBuilder sql = new StringBuilder();
		sql.append("UPDATE pedido SET impressoCozinha = true where pedido.codigo = :codigo");		

		try {
			session = getSessionAberta();
			SQLQuery sqlQuery = session.createSQLQuery(sql.toString());
			sqlQuery.setLong("codigo", codPedido);
			sqlQuery.executeUpdate();
		} catch (Exception e) {
			throw new ApplicationException(e.getMessage());
		} finally {
			if (session != null)
				session.close();
		}
	}

    public ArrayList<PedidoVO> montarRelatorioPedido( Date dataInicialPedido, Date dataFinalPedido, Long codCliente, Long codProduto, Integer situacaoPedido, Boolean promocao ) throws ApplicationException {
		Session session = null;
		try {
			session = getSessionAberta();
			Criteria criteria = session.createCriteria(PedidoVO.class, "pedido");
			criteria.createAlias( "pedido.produtos", "produtoQuantidade");  
			
			if(codCliente != null && codCliente != 0){
				criteria.add(Restrictions.eq( "pedido.cliente.codigo", codCliente ));
			}
			if(codProduto != null && codProduto != 0){
				criteria.add(Restrictions.eq( "produtoQuantidade.produto.codigo", codProduto ));
			}
			if(situacaoPedido != null ){
				criteria.add(Restrictions.eq( "pedido.status", StatusPedidoEnum.getByValor(situacaoPedido)));
			}
			if(promocao != null){
				criteria.add(Restrictions.eq( "produtoQuantidade.promocao", promocao ));
			}
			criteria.add(Restrictions.between( "pedido.dataHoraEmissao", TreatDate.clearDateTime(dataInicialPedido), TreatDate.clearLimitDateTime(dataFinalPedido )));
			criteria.addOrder(Order.asc("pedido.codigo"));
			
			return filtro(criteria);
		} catch (Exception e) {
			throw new ApplicationException(e.getMessage());
		} finally {
			if (session != null)
				session.close();
		}
    }


}
